home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1996 March / EnigmA AMIGA RUN 05 (1996)(G.R. Edizioni)(IT)[!][issue 1996-03][Skylink CD IV].iso / earcd / library / queue.lzh / queue / queue_library.c < prev    next >
C/C++ Source or Header  |  1995-10-18  |  9KB  |  405 lines

  1. /*
  2.    queue_library.c --- queue library interface.
  3.  
  4.    (c) Copyright 1995 SHW Wabnitz
  5.    Written by Bernhard Fastenrath (fasten@shw.com)
  6.  
  7.    This file may be distributed under the terms
  8.    of the GNU General Public License.
  9. */
  10.  
  11. #if defined (__GNUC__)
  12. #include <stabs.h>
  13. #endif
  14.  
  15. #include "queue_library.h"
  16.  
  17. struct ExecBase *SysBase = NULL;
  18. struct DosLibrary *DOSBase = NULL;
  19. struct Library *QueueBase = NULL;
  20. struct List Queues;
  21. ULONG ClientsListBusy = 0;
  22.  
  23. #if defined (__GNUC__)
  24. const BYTE LibName[] = "queue.library";
  25. const BYTE LibIdString[] = "$VER: queue.library 1.0 (10-10-95)";
  26. const UWORD LibVersion = 1;
  27. const UWORD LibRevision = 0;
  28. #endif
  29.  
  30. #if defined (__GNUC__)
  31. #define LIBRT
  32. #define REG(regname)
  33. #define STRUCT_MYLIB struct Library
  34. #else
  35. #define LIBRT __saveds __asm
  36. #define REG(reg-name) register __regname
  37. #define ADDTABL_1(name,arg1);
  38. #define ADDTABL_2(name,arg1,arg2);
  39. #define ADDTABL_3(name,arg1,arg2,arg3);
  40. #define ADDTABL_END();
  41. #define STRUCT_MYLIB struct MyLibrary
  42. #endif
  43.  
  44. /*** internal functions ***/
  45.  
  46. static ULONG
  47. strlen (char *name)
  48. {
  49.   ULONG t = 0;
  50.  
  51.   while (name[t])
  52.     t++;
  53.   return t;
  54. }
  55.  
  56. static void
  57. RemoveAndReply (QMessage *msg)
  58. {
  59.   QueueHandle *qh;
  60.  
  61.   if (!msg -> qm_Refs)
  62.   {
  63.     qh = (QueueHandle *) msg -> qm_Owner;
  64.     Remove ((Node *) msg);
  65.     /*** reply to owner ***/
  66.     Forbid ();
  67.     AddHead (&qh -> qh_un.qhs.qhs_ReplyList, (Node *) msg);
  68.     Signal (qh -> qh_SigTask, qh -> qh_SigMask);
  69.     Permit ();
  70.   }
  71.   else
  72.     msg -> qm_Status = QMS_REMOVED;
  73. }
  74.  
  75. static void
  76. ReplyQMessage (QueueNode *qn, QMessage *msg)
  77. {
  78.   msg -> qm_Refs --;
  79.   msg -> qm_Replies ++;
  80.  
  81.   if (msg -> qm_Replies >= qn -> qn_Read || msg -> qm_Status == QMS_REMOVED)
  82.     RemoveAndReply (msg);
  83. }
  84.  
  85. static void
  86. cleanup (void)
  87. {
  88.   if (DOSBase)
  89.     CloseLibrary ((struct Library *) DOSBase);
  90.   DOSBase = NULL;
  91. }
  92.  
  93. /*** library interface ***/
  94.  
  95. int LIBRT
  96. __UserLibInit (REG(a6) STRUCT_MYLIB *libbase)
  97. {
  98.   SysBase = *(struct ExecBase **)4;
  99.   QueueBase = (struct Library *) libbase;
  100.  
  101.   if (!(DOSBase = (struct DosLibrary *) OpenLibrary ("dos.library", 37)))
  102.     return 1;
  103.   NewList (&Queues);
  104.   return 0; /* success */
  105. }
  106.  
  107. void LIBRT
  108. __UserLibCleanup (REG(a6) STRUCT_MYLIB *libbase)
  109. {
  110.   cleanup ();
  111. }
  112.  
  113. ADDTABL_3(LIBQOpen,a0,d0,d1);
  114.  
  115. QHandle LIBRT
  116. LIBQOpen (REG(a0) STRPTR name, REG(d0) ULONG mode, REG(d1) ULONG sigbit)
  117. {
  118.   QueueHandle *qh;
  119.   QueueNode *qn;
  120.   ULONG len;
  121.  
  122.   if (!(qh = (QueueHandle *) AllocMem (sizeof (QueueHandle), MEMF_PUBLIC | MEMF_CLEAR)))
  123.     return NULL;
  124.  
  125.   Forbid ();
  126.   if (!(qn = (QueueNode *) FindName (&Queues, name)))
  127.   {
  128.     if (!(qn = AllocMem (sizeof (QueueNode), MEMF_PUBLIC | MEMF_CLEAR)))
  129.     {
  130.       FreeMem (qh, sizeof (QueueHandle));
  131.       Permit ();
  132.       return NULL;
  133.     }
  134.     len = strlen (name) + 1;
  135.     if (!(qn -> qn_Node.ln_Name = AllocMem (len, MEMF_PUBLIC)))
  136.     {
  137.       FreeMem (qh, sizeof (QueueHandle));
  138.       FreeMem (qh, sizeof (QueueNode));
  139.       Permit ();
  140.       return NULL;
  141.     }
  142.     CopyMem (name, qn -> qn_Node.ln_Name, len);
  143.     AddHead (&Queues, (Node *) qn);
  144.     NewList (&qn -> qn_Handles);
  145.     NewList (&qn -> qn_List);
  146.   }
  147.   qn -> qn_Refs ++;
  148.   AddHead (&qn -> qn_Handles, (Node *) qh);
  149.   qh -> qh_Mode    = mode;
  150.   qh -> qh_QNode   = qn;
  151.   qh -> qh_SigMask = 1 << sigbit;
  152.   qh -> qh_SigTask = FindTask (0);
  153.   if (mode == QMODE_LISTEN)
  154.   {
  155.     qn -> qn_Read ++;
  156.     qh -> qh_un.qhl.qhl_Status = QMS_MARKER;
  157.     Signal (qh -> qh_SigTask, qh -> qh_SigMask);
  158.   }
  159.   else
  160.   {
  161.     NewList (&qh -> qh_un.qhs.qhs_ReplyList);
  162.   }
  163.   Permit ();
  164.   return (QHandle) qh;
  165. }
  166.  
  167. ADDTABL_1(LIBQClose,a0);
  168.  
  169. ULONG LIBRT
  170. LIBQClose (REG(a0) QHandle qhandle)
  171. {
  172.   QueueNode *qn = ((QueueHandle *) qhandle) -> qh_QNode;
  173.   QueueHandle *qh = qhandle;
  174.   QMessage *cmsg, *msg, *next;
  175.  
  176.   Forbid ();
  177.   if (qh -> qh_Mode == QMODE_SEND)
  178.   {
  179.     if (qh -> qh_un.qhs.qhs_MsgCount)
  180.     {
  181.       Permit ();
  182.       return qh -> qh_un.qhs.qhs_MsgCount;
  183.     }
  184.   }
  185.   else
  186.   {
  187.     if (cmsg = (QMessage *) qh -> qh_un.qhl.qhl_MinNode.mln_Succ)
  188.     {
  189.       Remove ((Node *) &qh -> qh_un.qhl.qhl_MinNode); /* Remove marker */
  190.       next = cmsg;
  191.     }
  192.     else
  193.     {
  194.       if (cmsg = qh -> qh_un.qhl.qhl_Message)
  195.         next = (QMessage *) cmsg -> qm_MinNode.mln_Pred;
  196.     }
  197.     if (cmsg)
  198.     {
  199.       for (msg = next; next = (QMessage *) msg -> qm_MinNode.mln_Pred;
  200.        msg = next)
  201.       {
  202.     /* Replies from the current task
  203.        don't count after QClose().
  204.         */
  205.     if (msg -> qm_Status == QMS_ACTIVE)
  206.       msg -> qm_Replies --;
  207.       }
  208.     }
  209.     if (!cmsg)
  210.       cmsg = (QMessage *) qn -> qn_List.lh_Head;
  211.  
  212.     for (msg = cmsg; next = (QMessage *) msg -> qm_MinNode.mln_Succ; msg = next)
  213.     {
  214.       /* These messages might be in the queue, waiting only
  215.      for the current task; let's give them a chance.
  216.       */
  217.       if ((msg -> qm_Status == QMS_ACTIVE && msg -> qm_Replies >= qn -> qn_Read)
  218.     || msg -> qm_Status == QMS_REMOVED)
  219.       {
  220.         RemoveAndReply (msg);
  221.       }
  222.       if (msg -> qm_Status == QMS_MARKER)
  223.     break;
  224.     }
  225.     qn -> qn_Read --;
  226.   }
  227.   Remove ((Node *) qhandle);
  228.   FreeMem (qhandle, sizeof (QueueHandle));
  229.   if (! -- qn -> qn_Refs)
  230.   {
  231.     Remove ((Node *) qn);
  232.     FreeMem (qn -> qn_Node.ln_Name, strlen (qn -> qn_Node.ln_Name) + 1);
  233.     FreeMem (qn, sizeof (QueueNode));
  234.   }
  235.   Permit ();
  236.   return 0;
  237. }
  238.  
  239. ADDTABL_2(LIBQAddMsg,a0,a1);
  240.  
  241. void LIBRT
  242. LIBQAddMsg (REG(a0) QHandle qhandle, REG(a1) QMessage *msg)
  243. {
  244.   QueueNode *qn = ((QueueHandle *) qhandle) -> qh_QNode;
  245.   QueueHandle *qh = (QueueHandle *) qhandle;
  246.  
  247.   msg -> qm_Owner   = qhandle;
  248.   msg -> qm_Refs    = 0;
  249.   msg -> qm_Replies = 0;
  250.   msg -> qm_Status  = QMS_ACTIVE;
  251.   Forbid ();
  252.   AddTail (&qn -> qn_List, (Node *) msg);
  253.   qh -> qh_un.qhs.qhs_MsgCount ++;
  254.   if (qn -> qn_Read)
  255.   {
  256.     for (qh = (QueueHandle *) qn -> qn_Handles.lh_Head; qh -> qh_MinNode.mln_Succ;
  257.          qh = (QueueHandle *) qh -> qh_MinNode.mln_Succ)
  258.     {
  259.       if (qh -> qh_Mode == QMODE_LISTEN)
  260.         Signal (qh -> qh_SigTask, qh -> qh_SigMask);
  261.     }
  262.   }
  263.   else
  264.     RemoveAndReply (msg);
  265.   Permit ();
  266. }
  267.  
  268. ADDTABL_2(LIBQRemMsg,a0,a1);
  269.  
  270. void LIBRT
  271. LIBQRemMsg (REG(a0) QHandle qhandle, REG(a1) QMessage *msg)
  272. {
  273.   QueueNode *qn = ((QueueHandle *) qhandle) -> qh_QNode;
  274.  
  275.   Forbid ();
  276.   RemoveAndReply (msg);
  277.   Permit ();
  278. }
  279.  
  280. ADDTABL_1(LIBQGetMsg,a0);
  281.  
  282. QMessage * LIBRT
  283. LIBQGetMsg (REG(a0) QHandle qhandle)
  284. {
  285.   QueueNode *qn = ((QueueHandle *) qhandle) -> qh_QNode;
  286.   QueueHandle *qh = (QueueHandle *) qhandle;
  287.   QMessage *msg, *next;
  288.  
  289.   Forbid ();
  290.  
  291.   /* A server ( QMODE_SEND ) retrieves a replied message */
  292.  
  293.   if (qh -> qh_Mode == QMODE_SEND)
  294.   {
  295.     if (msg = (QMessage *) RemTail (&qh -> qh_un.qhs.qhs_ReplyList))
  296.       qh -> qh_un.qhs.qhs_MsgCount --;
  297.     Permit ();
  298.     return msg;
  299.   }
  300.  
  301.   /* A client ( QMODE_LISTEN ) reads a message */
  302.  
  303.   if (msg = qh -> qh_un.qhl.qhl_Message)
  304.   {
  305.     /* automagically reply the current message */
  306.  
  307.     next = (QMessage *) msg -> qm_MinNode.mln_Succ;
  308.     ReplyQMessage (qn, msg);
  309.     msg = next;
  310.   }
  311.   else /* no current message, start at marker or list head */
  312.   {
  313.     if (msg = (QMessage *) qh -> qh_un.qhl.qhl_MinNode.mln_Succ)
  314.     {
  315.       Remove ((Node *) &qh -> qh_un.qhl.qhl_MinNode);
  316.       qh -> qh_un.qhl.qhl_MinNode.mln_Succ = NULL;
  317.     }
  318.     else
  319.       msg = (QMessage *) qn -> qn_List.lh_Head;
  320.   }
  321.   for (;;)
  322.   {
  323.     if (!(next = (QMessage *) msg -> qm_MinNode.mln_Succ))
  324.     {
  325.       msg = NULL;
  326.       break;
  327.     }
  328.     if (msg -> qm_Status & QMS_INACTIVE)
  329.     {
  330.       if (msg -> qm_Status == QMS_REMOVED)
  331.         RemoveAndReply (msg);
  332.       msg = next;
  333.       continue;
  334.     }
  335.     msg -> qm_Refs ++;
  336.     break;
  337.   }
  338.   qh -> qh_un.qhl.qhl_Message = msg;
  339.   Permit ();
  340.   return msg;
  341. }
  342.  
  343. ADDTABL_1(LIBQReplyMsg,a0);
  344.  
  345. ULONG LIBRT
  346. LIBQReplyMsg (REG(a0) QHandle qhandle)
  347. {
  348.   QueueNode *qn = ((QueueHandle *) qhandle) -> qh_QNode;
  349.   QueueHandle *qh = (QueueHandle *) qhandle;
  350.   QMessage *msg, *next;
  351.  
  352.   if (!(msg = qh -> qh_un.qhl.qhl_Message))
  353.     return 0;
  354.  
  355.   Forbid ();
  356.  
  357.   /* Set marker */
  358.   if (qh -> qh_un.qhl.qhl_MinNode.mln_Succ)
  359.     Remove ((Node *) &qh -> qh_un.qhl.qhl_MinNode);
  360.   Insert (&qn -> qn_List, (Node *) &qh -> qh_un.qhl.qhl_MinNode, (Node *) msg);
  361.  
  362.   next = (QMessage *) msg -> qm_MinNode.mln_Succ;
  363.   ReplyQMessage (qn, msg);
  364.  
  365.   if (next)
  366.   {
  367.     for (msg = next; next = (QMessage *) msg -> qm_MinNode.mln_Succ; msg = next)
  368.     {
  369.       if (msg -> qm_Status == QMS_ACTIVE)
  370.       {
  371.     /* Since QReplyMsg() means you're not going to read more messages now
  372.        it's probably a good idea to remind you that there's more.
  373.     */
  374.     Signal (qh -> qh_SigTask, qh -> qh_SigMask);
  375.     break;
  376.       }
  377.     }
  378.   }
  379.   qh -> qh_un.qhl.qhl_Message = NULL;
  380.   Permit ();
  381.   return 1;
  382. }
  383.  
  384. ADDTABL_1(LIBQFlush,a0);
  385.  
  386. ULONG LIBRT
  387. LIBQFlush (REG(a0) QHandle qhandle)
  388. {
  389.   QueueNode *qn = ((QueueHandle *) qhandle) -> qh_QNode;
  390.   QMessage *msg, *next;
  391.  
  392.   Forbid ();
  393.   msg = (QMessage *) qn -> qn_List.lh_Head;
  394.   while (next = (QMessage *) msg -> qm_MinNode.mln_Succ)
  395.   {
  396.     RemoveAndReply (msg);
  397.     msg = next;
  398.   }
  399.   Permit ();
  400.   return 1;
  401. }
  402.  
  403. ADDTABL_END();
  404.  
  405.